use crate::entity::{prelude::SysPost, sys_post};
use ane_macros::{model_fetch, model_list};
use sea_orm::{
    ActiveModelTrait, ColumnTrait, ConnectionTrait, DbConn, DerivePartialModel, FromQueryResult,
    PartialModelTrait, Set,
};
use serde::{Deserialize, Serialize};
use validator::Validate;

use super::Result;

#[derive(Debug, DerivePartialModel, FromQueryResult, Serialize)]
#[sea_orm(entity = "SysPost")]
pub struct PostSimpleVo {
    pub id: i32,
    pub name: String,
    pub key: String,
}

#[derive(Debug, DerivePartialModel, FromQueryResult, Serialize)]
#[sea_orm(entity = "SysPost")]
pub struct PostVo {
    pub id: i32,
    pub name: String,
    pub key: String,
    pub description: String,
    pub status: bool,
}

#[derive(Debug, Deserialize, Validate)]
pub struct PostDo {
    #[validate(length(min = 3, max = 32), non_control_character)]
    pub name: String,
    #[validate(length(min = 3, max = 32), non_control_character)]
    pub key: String,
    pub data_scope: Option<i8>,
    pub description: Option<String>,
    pub status: Option<bool>,
}

pub struct Post;

impl Post {
    model_list!(
        #model =sys_post
        #filter=[DelFlag.eq(0)]
        /// 根据条件列出Post
        /// ## params
        /// - `name:Option<String>`  post名称 contains
        /// - `key:Option<String>`   post key contains
        /// - `status:Option<bool>`  true启用，false停用
        pub fn list(Name.contains(name:Option<String>), Key.contains(key:Option<String>), Status.eq(status:Option<bool>))
    );

    model_fetch!(
        #model =sys_post
        #filter=[DelFlag.eq(0)]
        pub fn get_by_id(Id.eq(id:i32))
    );

    model_fetch!(
        #model =sys_post
        #filter=[DelFlag.eq(0)]
        pub fn get_by_key(Key.eq(key:&str))
    );

    pub async fn create(db: &impl ConnectionTrait, data: PostDo) -> Result<sys_post::Model> {
        sys_post::ActiveModel {
            name: Set(data.name),
            key: Set(data.key),
            description: Set(data.description.unwrap_or("".to_owned())),
            data_scope: Set(data.data_scope.unwrap_or(5)),
            status: Set(data.status.unwrap_or(false)),
            del_flag: Set(0),
            ..Default::default()
        }
        .insert(db)
        .await
    }

    pub async fn update_post(
        db: &impl ConnectionTrait,
        id: i32,
        data: PostDo,
    ) -> Result<sys_post::Model> {
        sys_post::ActiveModel {
            id: Set(id),
            name: Set(data.name),
            key: Set(data.key),
            description: data.description.map(Set).unwrap_or_default(),
            data_scope: data.data_scope.map(Set).unwrap_or_default(),
            status: data.status.map(Set).unwrap_or_default(),
            ..Default::default()
        }
        .update(db)
        .await
    }

    pub async fn delete(db: &impl ConnectionTrait, id: i32) -> Result<u64> {
        sys_post::ActiveModel {
            id: Set(id),
            ..Default::default()
        }
        .delete(db)
        .await
        .map(|r| r.rows_affected)
    }
}
